﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace PonGun
{
    public class GSM
    {
        List<Screen> Screens = new List<Screen>();
        protected Game1 Game;

        public string LastScreen { get; set; }
        public string CurrentScreen { get; set; }
        public string NextScreen { get; set; }

        public Screen ThisScreen { get { return Screens.SingleOrDefault(screen => screen.Name == CurrentScreen); } }

        public MousePointer MousePointer;

        List<Vector2> L1 = new List<Vector2>();
        List<float> L1Speed = new List<float>();

        List<Vector2> L2 = new List<Vector2>();
        List<float> L2Speed = new List<float>();

        List<Vector2> L3 = new List<Vector2>();
        List<float> L3Speed = new List<float>();

        List<Vector2> L1VP = new List<Vector2>();
        List<Vector2> L2VP = new List<Vector2>();
        List<Vector2> L3VP = new List<Vector2>();

        public SoundEffectInstance music;
        public float musicMaxVolume = .25f;

        public GSM(Game1 game)
        {
            Game = game;
            LastScreen = CurrentScreen = NextScreen = string.Empty;

            MousePointer = new MousePointer(Game);

            int x, y;
            float sp;

            int lCnt = 256;

            for (int s = 0; s < lCnt; s++)
            {
                x = (int)MathHelper.Lerp(Game1.RenderArea.X, Game1.RenderArea.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble());
                sp = MathHelper.Lerp(1, 2, (float)Game1.rnd.NextDouble());
                L1.Add(new Vector2(x, y));
                L1Speed.Add(sp);

                x = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.X, Game.GraphicsDevice.Viewport.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble());
                L1VP.Add(new Vector2(x, y));
            }

            for (int s = 0; s < lCnt/2; s++)
            {
                x = (int)MathHelper.Lerp(Game1.RenderArea.X, Game1.RenderArea.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble());
                sp = MathHelper.Lerp(2, 3, (float)Game1.rnd.NextDouble());
                L2.Add(new Vector2(x, y));
                L2Speed.Add(sp);

                x = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.X, Game.GraphicsDevice.Viewport.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble());
                L2VP.Add(new Vector2(x, y));
            }

            for (int s = 0; s < lCnt/4; s++)
            {
                x = (int)MathHelper.Lerp(Game1.RenderArea.X, Game1.RenderArea.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble());
                sp = MathHelper.Lerp(3, 4, (float)Game1.rnd.NextDouble());
                L3.Add(new Vector2(x, y));
                L3Speed.Add(sp);

                x = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.X, Game.GraphicsDevice.Viewport.Width, (float)Game1.rnd.NextDouble());
                y = (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble());
                L3VP.Add(new Vector2(x, y));
            }
        }



        public void AddScreen(Screen screen)
        {
            Screens.Add(screen);
        }

        public void NavigateTo(string screenName)
        {
            NextScreen = screenName;
            ThisScreen.State = ScreenStates.FadingOut;
        }

        public void Update(GameTime gameTime)
        {
            if (music == null)
            {
                music = Game.Content.Load<SoundEffect>("Audio/Music/PonGunMenuMusic").CreateInstance();
                music.IsLooped = true;
                music.Volume = musicMaxVolume;
                music.Play();
            }

            for (int s = 0; s < L1.Count; s++)
            {
                L1[s] = new Vector2(L1[s].X + L1Speed[s], L1[s].Y);
                if (L1[s].X > Game1.RenderArea.Width)
                {
                    L1[s] = new Vector2(0, (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble()));
                    L1Speed[s] = MathHelper.Lerp(1, 2, (float)Game1.rnd.NextDouble());
                }

                L1VP[s] = new Vector2(L1VP[s].X + L1Speed[s], L1VP[s].Y);
                if (L1VP[s].X > Game.GraphicsDevice.Viewport.Width)
                {
                    L1VP[s] = new Vector2(0, (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble()));
                    L1Speed[s] = MathHelper.Lerp(1, 2, (float)Game1.rnd.NextDouble());
                }
            }

            for (int s = 0; s < L2.Count; s++)
            {
                L2[s] = new Vector2(L2[s].X + L2Speed[s], L2[s].Y);
                if (L2[s].X > Game1.RenderArea.Width)
                {
                    L2[s] = new Vector2(0, (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble()));
                    L2Speed[s] = MathHelper.Lerp(2, 3, (float)Game1.rnd.NextDouble());
                }

                L2VP[s] = new Vector2(L2VP[s].X + L2Speed[s], L2VP[s].Y);
                if (L2VP[s].X > Game.GraphicsDevice.Viewport.Width)
                {
                    L2VP[s] = new Vector2(0, (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble()));
                    L2Speed[s] = MathHelper.Lerp(1, 2, (float)Game1.rnd.NextDouble());
                }
            }

            for (int s = 0; s < L3.Count; s++)
            {
                L3[s] = new Vector2(L3[s].X + L3Speed[s], L3[s].Y);
                if (L3[s].X > Game1.RenderArea.Width)
                {
                    L3[s] = new Vector2(0, (int)MathHelper.Lerp(Game1.RenderArea.Y, Game1.RenderArea.Height, (float)Game1.rnd.NextDouble()));
                    L3Speed[s] = MathHelper.Lerp(3, 4, (float)Game1.rnd.NextDouble());
                }

                L3VP[s] = new Vector2(L3VP[s].X + L3Speed[s], L3VP[s].Y);
                if (L3VP[s].X > Game.GraphicsDevice.Viewport.Width)
                {
                    L3VP[s] = new Vector2(0, (int)MathHelper.Lerp(Game.GraphicsDevice.Viewport.Y, Game.GraphicsDevice.Viewport.Height, (float)Game1.rnd.NextDouble()));
                    L3Speed[s] = MathHelper.Lerp(1, 2, (float)Game1.rnd.NextDouble());
                }
            }

            switch (ThisScreen.State)
            {
                case ScreenStates.FadingIn:
                    ThisScreen.opacity += ThisScreen.FadeSpeed;
                    if (ThisScreen.opacity >= 1)
                    {
                        ThisScreen.opacity = 1;
                        ThisScreen.State = ScreenStates.FadedIn;
                    }
                    break;
                case ScreenStates.FadingOut:
                    ThisScreen.opacity -= ThisScreen.FadeSpeed;
                    if (ThisScreen.opacity <= 0)
                    {
                        ThisScreen.opacity = 0;
                        ThisScreen.State = ScreenStates.FadedOut;
                        ThisScreen.CloseDown();
                        LastScreen = CurrentScreen;
                        CurrentScreen = NextScreen;
                        NextScreen = string.Empty;
                        ThisScreen.State = ScreenStates.FadingIn;
                    }
                    break;
                case ScreenStates.FadedIn:
                    ThisScreen.opacity = 1;
                    break;
                case ScreenStates.FadedOut:
                    ThisScreen.opacity = 0;
                    break;
            }

            MousePointer.Update(gameTime);
            ThisScreen.Update(gameTime);
        }

        Color stColor1 = new Color(1f, 1f, 1f, .25f);
        Color stColor2 = new Color(1f, 1f, 1f, .5f);
        Color stColor3 = new Color(1f, 1f, 1f, .75f);

        public void Draw(GameTime gameTime)
        {
            DrawStars(gameTime);

            ThisScreen.Draw(gameTime);
            if (ThisScreen.HasMouse)
                MousePointer.Draw(gameTime);
            Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/black"), Game1.RenderArea, new Color(1f, 1f, 1f, 1-ThisScreen.opacity));
        }

        public void DrawStars(GameTime gameTime)
        {
            if (ThisScreen.StarFieldOn)
            {
                foreach (Vector2 v in L1)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 2, 1), stColor1);

                foreach (Vector2 v in L2)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 4, 2), stColor2);

                foreach (Vector2 v in L3)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 6, 3), stColor3);
            }
        }

        public void DrawStarsVP(GameTime gameTime)
        {
            if (ThisScreen.StarFieldOn)
            {
                foreach (Vector2 v in L1VP)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 2, 1), stColor1);

                foreach (Vector2 v in L2VP)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 4, 2), stColor2);

                foreach (Vector2 v in L3VP)
                    Game.spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/white"), new Rectangle((int)v.X, (int)v.Y, 6, 3), stColor3);
            }
        }
    }

    public enum ScreenStates
    {
        FadingIn,
        FadedIn,
        FadingOut,
        FadedOut,
        Paused,
    }

    public class Screen : Base2DObject
    {
        public float FadeSpeed { get; set; }
        public float opacity = 0;

        public bool HasMouse { get; set; }
        public bool StarFieldOn { get; set; }

        public ScreenStates State = ScreenStates.FadingIn;

        public GSM GSM;

        public Screen(Game1 game, GSM gsm) : base(game) 
        {
            GSM = gsm;
            FadeSpeed = .01f;

            Width = Game1.RenderArea.Width;
            Height = Game1.RenderArea.Height;

            Position = Game1.RenderAreaCenter;
            HasMouse = true;
            StarFieldOn = true;
        }

        public virtual void CloseDown() { }
    }
}
